#pragma once
#include"../muduo/buffer.hpp"
#include "util.hpp"
#include "http.hpp"

namespace Http
{
#define MAX_LINE 8192
    typedef enum
    {
        RECV_HTTP_ERROR,//接收处理数据出错
        RECV_HTTP_LINE,//接收请求行
        RECV_HTTP_HEAD,//接收请求头部
        RECV_HTTP_BODY,//接收请求正文
        RECV_HTTP_OVER//接收数据完毕
    }HttpRecvStatu;

    class HttpContext
    {
    public:
        HttpContext():_resp_statu(200),_recv_statu(RECV_HTTP_LINE){}
        //重置
        void ReSet()
        {
            _resp_statu = 200;
            _recv_statu = RECV_HTTP_LINE;
            _request.ReSet();
        }

        //获取响应状态码
        int RespStatu()
        {
            return _resp_statu;
        }

        //获取接收状态
        HttpRecvStatu RecvStatu()
        {
            return _recv_statu;
        }

        //获取请求信息
        HttpRequest & Request()
        {
            return _request;
        }

        //接收并解析HTTP请求
        void RecvHttpRequest(Muduo::Buffer * buf)
        {
            //状态机
            switch(_recv_statu)
            {
                case RECV_HTTP_LINE:RecvHttpLine(buf);
                case RECV_HTTP_HEAD:RecvHttpHead(buf);
                case RECV_HTTP_BODY:RecvHttpBody(buf);
            }
        }

    private:
        //解析Http请求请求行
        bool ParseHttpLine(const std::string & line)
        {
            std::smatch matches;
            std::regex e("(GET|HEAD|POST|PUT|DELETE) ([^?]*)(?:\\?(.*))? (HTTP/1\\.[01])(?:\n|\r\n)?",std::regex::icase);//忽略大小写
            bool ret = std::regex_match(line,matches,e);
            if(ret == false)
            {
                _recv_statu = RECV_HTTP_ERROR;
                _resp_statu = 400;//Bad Request
                return false;
            }
            _request._method = matches[1];//请求方法
            //转换为大写
            std::transform(_request._method.begin(), _request._method.end(), _request._method.begin(),toupper);
            _request._path = Util::UrlDecode(matches[2],false);//资源路径
            _request._version = matches[4];//协议版本
            std::vector<std::string> query_string_array;
            std::string query_string = matches[3];//查询字符串
            Util::Split(query_string,"&",&query_string_array);
            for(auto & str:query_string_array)
            {
                size_t pos = str.find('=');
                if(pos == std::string::npos)
                {
                    _recv_statu = RECV_HTTP_ERROR;
                    _resp_statu = 400;
                    return false;
                }
                std::string key = Util::UrlDecode(str.substr(0,pos),true);
                std::string val = Util::UrlDecode(str.substr(pos+1),true);
                _request.SetParam(key,val);
            }
            return true;
        }

        //接收Http请求请求行
        bool RecvHttpLine(Muduo::Buffer * buf)
        {
            if(_recv_statu != RECV_HTTP_LINE) return false;
            std::string line = buf->GetLineAndPop();//获取一行数据
            if(line.size() == 0)
            {
                //不足一行或者一行数据过多
                if(buf->ReadAbleSize()>MAX_LINE)
                {
                    _recv_statu = RECV_HTTP_ERROR;
                    _resp_statu = 414;//URI Too Long
                    return false;
                }
                return true;
            }
            //请求行长度太长
            if(line.size()>MAX_LINE)
            {
                _recv_statu = RECV_HTTP_ERROR;
                _resp_statu = 414;
                return false;
            }
            bool ret = ParseHttpLine(line);
            if(ret == false)    return false;
            _recv_statu = RECV_HTTP_HEAD;
            return true;
        }

        //接收Http请求头
        bool RecvHttpHead(Muduo::Buffer * buf)
        {
            if(_recv_statu != RECV_HTTP_HEAD) return false;
            //遇到空行截止,key: val\r\nkey: val\r\n
            while(true)
            {
                std::string line = buf->GetLineAndPop();
                if(line.size() == 0)
                {
                    if(buf->ReadAbleSize()>MAX_LINE)
                    {
                        _recv_statu = RECV_HTTP_ERROR;
                        _resp_statu = 414;
                        return false;
                    }
                    return true;
                }
                if(line.size()>MAX_LINE)
                {
                    _recv_statu = RECV_HTTP_ERROR;
                    _resp_statu = 414;
                    return false;
                }
                if(line == "\n"||line == "\r\n")
                {
                    break;
                }
                bool ret = ParseHttpHead(line);
                if(ret == false)
                {
                    return false;
                }
            }
            //头部处理完毕,进入正文获取阶段
            _recv_statu = RECV_HTTP_BODY;
            return true;
        }

        //解析Http请求头
        bool ParseHttpHead(std::string & line)
        {
            //去掉末尾的换行和回车
            if(line.back() == '\n') line.pop_back();
            if(line.back() == '\r') line.pop_back();
            size_t pos = line.find(": ");
            if(pos == std::string::npos)
            {
                _recv_statu = RECV_HTTP_ERROR;
                _resp_statu = 400;
                return false;
            }
            std::string key = line.substr(0,pos);
            std::string val = line.substr(pos+2);
            _request.SetHeader(key,val);
            return true;
        }

        //接收Http请求正文
        bool RecvHttpBody(Muduo::Buffer * buf)
        {
            if(_recv_statu != RECV_HTTP_BODY) return false;
            //获取正文长度
            size_t content_length = _request.ContentLength();
            if(content_length == 0)
            {
                _recv_statu = RECV_HTTP_OVER;
                return true;
            }
            //接收正文放到body中
            size_t real_len = content_length-_request._body.size();
            //缓冲区包含了完整正文
            if(buf->ReadAbleSize()>=real_len)
            {
                _request._body.append(buf->ReadPosition(),real_len);
                buf->MoveReadOffset(real_len);
                _recv_statu = RECV_HTTP_OVER;
                return true;
            }
            //缓冲区数据不足
            _request._body.append(buf->ReadPosition(),buf->ReadAbleSize());
            buf->MoveReadOffset(buf->ReadAbleSize());
            return true;
        }
    private:
        int _resp_statu;//响应状态码
        HttpRecvStatu _recv_statu;//当前接收解析的阶段状态
        HttpRequest _request;//解析得到的请求信息
    };
}